﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    class MonitorKey : IMonitor
    {
        public struct KBDLLHOOKSTRUCT
        {
            public Int32 vkCode;
            public Int32 scanCode;
            public Int32 flags;
            public Int32 time;
            public IntPtr dwExtraInfo;
        }


        // Internal callback processing function
        private delegate IntPtr KeyboardHookHandler(int nCode, IntPtr wParam, IntPtr lParam);
        private static KeyboardHookHandler hookHandler = HookFunc;

        // Hook ID
        private static IntPtr hookID = IntPtr.Zero;

        // Result of monitored keys
        private static StringBuilder newText;

        // Initialize low level keyboard hook
        public MonitorKey()
        {
            hookID = SetHook(hookHandler);
            newText = new StringBuilder("");
        }

        // Remove low level keyboard hook
        public string DisposeHook()
        {
            UnhookWindowsHookEx(hookID);
            return newText.ToString();
        }

        // Registers hook with Windows API
        private static IntPtr SetHook(KeyboardHookHandler proc)
        {
            using (ProcessModule module = Process.GetCurrentProcess().MainModule)
                return SetWindowsHookEx(13, proc, GetModuleHandle(module.ModuleName), 0);

        }

        // Default hook call, which analyses pressed keys
        private static IntPtr HookFunc(
            int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                int flag = Marshal.ReadInt32(lParam);
                KBDLLHOOKSTRUCT kbd = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                flag = Marshal.ReadInt32(lParam+32);

                bool ctrlDown = Control.ModifierKeys == Keys.Control;

                // Sprawdz czy to jeden z klawiszy, ktore nas interesuja
                if (kbd.vkCode == 0x09 && kbd.flags == 0x20)
                {
                    Form1.user.KeyStats.AverageAltTabUsage++;                    
                }
                else if ((Keys)kbd.vkCode==Keys.Back)
                {
                    Form1.user.KeyStats.AverageBackspace++;
                }
                else if((Keys)kbd.vkCode==Keys.Enter)
                {
                    Form1.user.KeyStats.AverageEnterUsage++;
                }
                else if ((Keys)kbd.vkCode == Keys.V && ctrlDown)
                {
                    Form1.user.KeyStats.AveragePasteUsage++;
                }
                else if ((Keys)kbd.vkCode == Keys.C && ctrlDown)
                {
                    Form1.user.KeyStats.AverageCopyUsage++;
                }
                else if ((Keys)kbd.vkCode == Keys.X && ctrlDown)
                {
                    Form1.user.KeyStats.AverageCutUsage++;
                }
                else if ((Keys)kbd.vkCode == Keys.S && ctrlDown)
                {
                    Form1.user.KeyStats.AverageSave++;
                }
                else
                {
                    newText.Append(((Keys)vkCode).ToString());
                }
                newText.Append(" ");
            }
            return CallNextHookEx(hookID, nCode, wParam, lParam);
        }

        // Low-Level function declarations
        #region WinAPI
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
            KeyboardHookHandler lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
            IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool ChangeClipboardChain(
            IntPtr hWndRemove,  // handle to window to remove
            IntPtr hWndNewNext  // handle to next window
            );

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

    }
        #endregion
}